﻿namespace LogicStudio.Framework.UI.Controles
{
    using System;
    using System.Diagnostics;
    using System.Windows;
    using System.Windows.Controls;
    using Utilidades;

    /// <summary>
    /// <see cref="ChildWindow"/> Clase que muestra los errores al usuario.
    /// </summary>
    public partial class VentanaError
    {
        #region Constructores

        /// <summary>
        /// Crea una nueva <see cref="VentanaError"/> instancia.
        /// </summary>
        /// <param name="mensaje">El mensaje del error a desplegar.</param>
        /// <param name="detalleError">Información adicional del error.</param>
        protected VentanaError(string mensaje, string detalleError)
        {
            Resources.Add("Recursos", RecursosLenguaje.Recursos);
            Style = RecursosFrameworkUI.ObtenerEstilo(RecursosFrameworkUI.NombreEstiloPopUp);
            InitializeComponent();
            IntroductoryText.Text = mensaje;
            ErrorTextBox.Text = detalleError;
        }

        #endregion

        #region Métodos Públicos

        /// <summary>
        /// Crea una nueva ventana de error partiendo de un mensaje.
        /// El seguimiento de la pila actual se mostrará si la aplicación se ejecuta en depuración o en la máquina local.
        /// </summary>
        /// <param name="mensaje">El mensaje a desplegar.</param>
        public static void Crear(string mensaje)
        {
            var recurso = RecursosLenguaje.Recursos;
            var texto = string.Empty;
            texto = recurso.GetType().GetProperty("TituloError").GetValue(texto, null).ToString();
            Crear(texto, mensaje);
        }

        /// <summary>
        /// Crea una nueva ventana de error partiendo de un mensaje.
        /// Seguimiento de la pila actual se mostrará si la aplicación se ejecuta en depuración o en la máquina local.
        /// </summary>
        /// <param name="titulo">Titulo del error</param>
        /// <param name="mensaje">El mensaje a desplegar.</param>
        public static void Crear(string titulo, string mensaje)
        {
            Crear(titulo, mensaje, PoliticaSeguimientoPila.SoloDepuracionYEjecucionLocal);
        }

        /// <summary>
        /// Crea una nueva ventana de error partiendo de una excepción.
        /// El seguimiento de la pila actual se mostrará si la aplicación se ejecuta en depuración o en la máquina local..
        /// La excepción se convierte en un mensaje usando <see cref="ConvertirExcepcionAMensaje"/>.
        /// </summary>
        /// <param name="titulo">Titulo del error</param>
        /// <param name="excepcion">La excepcion a desplegar.</param>
        public static void Crear(string titulo, Exception excepcion)
        {
            Crear(titulo, excepcion, PoliticaSeguimientoPila.SoloDepuracionYEjecucionLocal);
        }

        /// <summary>
        /// Crea una nueva ventana de error partiendo de una excepción.
        /// La excepción se convierte en un mensaje usando <see cref="ConvertirExcepcionAMensaje"/>.
        /// </summary>
        /// <param name="titulo">Titulo del error</param>
        /// <param name="excepcion">La excepcion a desplegar.</param>
        /// <param name="politica">Cuando visualizar el seguimiento de la pila, consulte <see cref="PoliticaSeguimientoPila"/>.</param>
        public static void Crear(string titulo, Exception excepcion, PoliticaSeguimientoPila politica)
        {
            if (excepcion == null)
            {
                throw new ArgumentNullException("excepcion");
            }

            var seguimientoErrorCompleto = excepcion.StackTrace;

            // Cuenta de las excepciones anidadas
            var excepcionInterna = excepcion.InnerException;
            while (excepcionInterna != null)
            {
                seguimientoErrorCompleto += "\nProvocada por: " + excepcion.Message + "\n\n" + excepcion.StackTrace;
                excepcionInterna = excepcionInterna.InnerException;
            }

            Crear(titulo, ConvertirExcepcionAMensaje(excepcion), seguimientoErrorCompleto, politica);
        }

        /// <summary>
        /// Crea una nueva ventana de error partiendo de un mensaje.
        /// </summary>
        /// <param name="titulo">Titulo del error</param>
        /// <param name="mensaje">El mensaje a desplegar.</param>
        /// <param name="policy">Cuando visualizar el seguimiento de la pila, consulte <see cref="PoliticaSeguimientoPila"/>.</param>
        public static void Crear(string titulo, string mensaje, PoliticaSeguimientoPila policy)
        {
            Crear(titulo, mensaje, new StackTrace().ToString(), policy);
        }

        #endregion

        #region Métodos Fábrica

        /// <summary>
        /// Todos los métodos de otras fábricas se traducirá en una llamada a este.
        /// </summary>
        /// <param name="titulo">Titulo del error</param>
        /// <param name="mensaje">El mensaje a desplegar</param>
        /// <param name="stackTrace">El seguimiento de pila de asociado</param>
        /// <param name="politica">Cuando el seguimiento de la pila debe añadirse al mensaje</param>
        private static void Crear(string titulo, string mensaje, string stackTrace, PoliticaSeguimientoPila politica)
        {
            var detalleError = string.Empty;

            if (politica == PoliticaSeguimientoPila.Siempre ||
                politica == PoliticaSeguimientoPila.SoloDepuracionYEjecucionLocal && EsEjecucionDepuradorOLocal)
            {
                detalleError = stackTrace ?? string.Empty;
            }

            var ventanaError = new VentanaError(mensaje, detalleError) { Title = titulo };
            ventanaError.Show();
        }
        #endregion

        #region Metódos Privados

        /// <summary>
        /// Devuelve si se ejecuta con adjuntado a un depurador o con el servidor local.
        /// </summary>
        private static bool EsEjecucionDepuradorOLocal
        {
            get
            {
                if (Debugger.IsAttached)
                {
                    return true;
                }

                if (Application.Current.Host.Source == null)
                {
                    return true;
                }

                var hostUrl = Application.Current.Host.Source.Host;
                return hostUrl.Contains("::1") || hostUrl.Contains("localhost") || hostUrl.Contains("127.0.0.1");
            }
        }

        /// <summary>
        /// Crea un mensaje amigable para el usuario dado una excepción. 
        /// Actualmente, este método devuelve el valor Exception.Message.
        /// Se puede modificar este método para tratar ciertas clases de excepción de manera diferente.
        /// </summary>
        /// <param name="e">La excepcion a convertir.</param>
        private static string ConvertirExcepcionAMensaje(Exception e)
        {
            return e.Message;
        }

        #endregion

        #region Eventos

        private void OkButtonClick(object sender, RoutedEventArgs e)
        {
            DialogResult = true;
        }

        #endregion
    }
}